/*
	CSS Preload plugin for jQuery
	Version 1.11
	
	Copyright (c) 2009-2010 Todd Northrop
	http://www.speednet.biz/
	
	June 26, 2010

	This library is free software; you can redistribute
	it and/or modify it under the terms of the GNU
	Lesser General Public License as published by the
	Free Software Foundation; either version 2.1 of the
	License, or (at your option) any later version.
	
	This library is distributed in the hope that it will
	be useful, but WITHOUT ANY WARRANTY; without even the
	implied warranty of MERCHANTABILITY or FITNESS FOR A
	PARTICULAR PURPOSE. See the GNU Lesser General Public
	License for more details.
	
	You should have received a copy of the GNU Lesser
	General Public License along with this library;
	Inc., 59 Temple Place, Suite 330, Boston,
	MA 02111-1307 USA
------------------------------------------------------*/

(function ($) {

$.cssPreload = {
	// $.cssPreload is a small, static extension of jQuery used to control
	// certain aspects of image preloading.  In many cases it will not be
	// used at all, because all of the image preloads from style sheets and
	// from within the page's HTML tags are handled automatically, simply
	// by including the cssPreload JavaScript file on the page.
	
	loadMax: 2,
		// loadMax is the maximum number of parallel preloads that
		// will take place.  This is done to avoid choking older browsers,
		// but feel free to set this to a number you feel comfortable with.

	add: function (img) {
		// Adds one or more image URLs to preload.
		// Can pass either a string (single URL) or an array of strings
		// (to preload multiple images).
		// If the preload cycle has already taken place, the image(s)
		// will immediately begin to preload.  Otherwise, the image(s)
		// will preload when all the other images found in the CSS
		// are processed.
		
		if (typeof(img) === "string") {
			hashTable[img] = 1;
			loadingStarted && queueHashedUrls();
		}
		else if ($.isArray(img)) {
			var i = img.length;
			
			while (i--) {
				hashTable[img[i]] = 1;
			}

			loadingStarted && queueHashedUrls();
		}
	},
	
	after: function (fn) {
		// Sets a function to call immediately after the last queued
		// image is preloaded. An array of image URLs that were
		// preloaded is passed to the function.
		// after()  can be called multiple times to have multiple
		// functions called after the preload is complete.
		// The function is only called once, even if additional images
		// are preloaded after the initial preload cycle takes place.
		// To have a function continue to be called after subsequent
		// preloads, add the following line of code to the end of the
		// function:
		// $.cssPreload.after(arguments.callee);
				
		if ($.isFunction(fn)) {
			postProc[postProc.length] = fn;
		}
	}
};

var count = 0,
	next = 0,
	loading = 0,
	hashTable = {},
	src = [],
	finished = [],
	$images = $([]),
	postProc = [],
	loadingStarted = false;

function loadNextImage() {

	if ((next < count) && (loading < $.cssPreload.loadMax)) {
		var i = next++;

		loading++;
		$images.add($("<img />")
			.bind("error load abort readystatechange", {index: i}, imageLoaded)
			.attr("src", src[i]));
	}
}

function imageLoaded(e) {
	var i = e.data.index;
	
	if (!finished[i]) {
		finished[i] = true;
		loading--;
		$(this).unbind();
		
		if (next < count) {
			window.setTimeout(loadNextImage, 15);
		}
		else {
			while (postProc.length) {
				(postProc.shift())(src);
			}
		}
	}
}

function queueHashedUrls() {
	var prop, x, loadnum;

	for (prop in hashTable) {
		src[count++] = prop;
	}
	
	hashTable = {};

	if (count > next) {
		loadnum = Math.min($.cssPreload.loadMax, count - next)
		
		for (x = 0; x < loadnum; x++) {
			window.setTimeout(loadNextImage, x * 30);
		}
	}
}

function parseHtml(html) {
	var matchTag, matchUrl,
		regexHtml = /<(?:"[^"]*"|'[^']*'|[^'">])*>/g,
		regexUrl = /\burl\((?:["']|&quot;|&apos;|&#3[49];)?(?=[^"')&]|&(?!quot;|apos;|#3[49];))((?:[^"')&]|&(?!quot;|apos;|#3[49];))+)(?:["']|&quot;|&apos;|&#3[49];)?\)/ig;
	
	while (matchTag = regexHtml.exec(html)) {
		
		while (matchUrl = regexUrl.exec(matchTag[0])) {
			hashTable[matchUrl[1]] = 1;
		}
	}
}

function parseCss(sheets, paths) {
	var i, baseUrl, rules, style, text, match, imports,
		regexUrl = /\burl\(["']?([^"')]+)["']?\)/ig,
		imp = [],
		impPath = [],
		impIndex = 0,
		sheetIndex = sheets.length;
	
	function pathOnly(url) {
		return url.slice(0, url.lastIndexOf('/') + 1);
	}

	function resolvePath(path) {
		return ((path.charAt(0) === "/") || (path.indexOf("://") !== -1))? path : baseUrl + path;
	}

	while (sheetIndex--) {
		
		try {
			if (paths && paths[sheetIndex]) {
				baseUrl = paths[sheetIndex];
			}
			else {
				baseUrl = pathOnly(sheets[sheetIndex].href || window.location.href);
			}
			
			rules = sheets[sheetIndex].cssRules || sheets[sheetIndex].rules;
			
			if ((rules) && (i = rules.length)) {
				
				while (i--) {
				
					if ((style = rules[i].style) && (text = style.cssText)) {
						
						while (match = regexUrl.exec(text)) {
							hashTable[resolvePath(match[1])] = 1;
						}
					}
					else {
						if (style = rules[i].styleSheet) {
							imp[impIndex++] = style;
						}
					}
					
				}
			}
			
			if ((!impIndex) && (imports = sheets[sheetIndex].imports) && (i = imports.length)) {
				
				while (i--) {
					impPath[impIndex] = resolvePath(pathOnly(imports[i].href));
					imp[impIndex++] = imports[i];
				}
			}
		}
		catch (e) { }
	}

	if (impIndex) {
		parseCss(imp, impPath);
	}
}

$(window)
	.load(function () {
		loadingStarted = true;
		parseCss(document.styleSheets);
		parseHtml($("body")[0].innerHTML);
		queueHashedUrls();
	})
	.unload(function () {
		$images = src = finished = null;
	});

})(jQuery);
